import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart';

typedef String Formatter(BuildContext context, DateTime now, DateTime datetime);

class DateTimeText extends StatefulWidget {
  static final _formatSameDay = DateFormat('HH:mm');
  static final _formatSameYear = DateFormat('MM-dd HH:mm');
  static final _formatOtherYear = DateFormat('yyyy-MM-dd HH:mm');

  final DateTime datetime;
  final Formatter formatter;
  final TextStyle textStyle;
  final TextAlign textAlign;

  DateTimeText(
    DateTime datetime, {
    this.formatter = _format,
    this.textStyle = const TextStyle(
      color: Color(0xFFBEBEBE),
      fontSize: 10,
    ),
    this.textAlign,
  }) : datetime = datetime.toLocal();

  @override
  State<StatefulWidget> createState() {
    return DateTimeState();
  }

  static String _format(BuildContext context, DateTime now, DateTime datetime) {
    if (now.year == datetime.year) {
      if (now.month == datetime.month && now.day == datetime.day) {
        return _formatSameDay.format(datetime);
      }
      return _formatSameYear.format(datetime);
    }
    return _formatOtherYear.format(datetime);
  }
}

class DateTimeState extends State<DateTimeText> with SingleTickerProviderStateMixin {
  ValueNotifier<DateTime> _timeNotifier;
  Ticker _ticker;

  @override
  void initState() {
    super.initState();

    _timeNotifier = ValueNotifier(DateTime.now());
    _ticker = createTicker(_frameCallback)..start();
  }

  @override
  void dispose() {
    _ticker.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<DateTime>(
      valueListenable: _timeNotifier,
      builder: (context, value, child) {
        return Text(
          widget.formatter(context, value, widget.datetime),
          style: widget.textStyle,
          textAlign: widget.textAlign,
        );
      },
    );
  }

  void _frameCallback(Duration elapsed) {
    final before = _timeNotifier.value;
    final now = DateTime.now();
    if (before.day != now.day || before.month != now.month || before.year != now.year) {
      _timeNotifier.value = now;
    }
  }
}
